﻿using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Novel.Server.Models;
using Novel.Server.Response;
using Microsoft.EntityFrameworkCore;
using System.Drawing;
using System.Drawing.Imaging;
using Novel.Server.Utils;

namespace Novel.Server.Controllers
{
    /// <summary>
    /// 负责登录和注册等操作
    /// </summary>
    [Route("api/auth")]
    [ApiController]
    public class AuthController : ControllerBase
    {

        private readonly NovelContext dbContext;
        private readonly IConfiguration conf;

        public AuthController(NovelContext context, IConfiguration configuration)
        {
            dbContext = context;
            conf = configuration;
        }

        /// <summary>
        /// 注册用户
        /// </summary>
        [HttpPost("reg")]
        public async Task<IActionResult> Register([FromBody] LoginDto dto)
        {
            var userCount = await dbContext.Users.CountAsync();
            var isAdmin = userCount == 0;
            var role = isAdmin ? "admin" : "user";

            if (await dbContext.Users.AnyAsync(u => u.Username == dto.Username))
                return Ok(ApiResponse.ErrorResponse("用户名已被占用", 200));

            var salt = GenerateSalt();
            var hashedPassword = HashPassword(dto.Password, salt);

            var now = DateTime.UtcNow;
            var user = new User
            {
                Username = dto.Username,
                PasswordHash = hashedPassword,
                Salt = salt,
                Role = role,
                CreatedAt = now,
                UpdatedAt = now,
                IsDeleted = false,
                Bio = "",
            };

            dbContext.Users.Add(user);

            await dbContext.SaveChangesAsync();

            await SignInWith(dto.Username, role);
            return Ok(ApiResponse.SuccessResponse(true));
        }

        /// <summary>
        /// 创建用户
        /// </summary>
        [Authorize(Roles = "admin")]
        [HttpPost("create")]
        public async Task<IActionResult> Create([FromBody] CreateDto dto)
        {
            if (await dbContext.Users.AnyAsync(u => u.Username == dto.Username))
            {
                return Ok(ApiResponse.ErrorResponse("用户名已被占用", 200));
            }

            var salt = GenerateSalt();
            var hashedPassword = HashPassword(dto.Password, salt);

            var now = DateTime.UtcNow;
            var user = new User
            {
                Username = dto.Username,
                PasswordHash = hashedPassword,
                Salt = salt,
                Role = dto.Role,
                CreatedAt = now,
                UpdatedAt = now,
                IsDeleted = false,
                Bio = "",
            };

            dbContext.Users.Add(user);
            await dbContext.SaveChangesAsync();

            return Ok(ApiResponse.SuccessResponse(true));
        }


        /// <summary>
        /// 登录
        /// </summary>
        [HttpPost("login")]
        public async Task<IActionResult> Login([FromBody] LoginDto dto)
        {
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.Username == dto.Username);
            if (user == null || user.IsDeleted) return Ok(ApiResponse.SuccessResponse(false));

            var hashedPassword = HashPassword(dto.Password, user.Salt);
            if (user.PasswordHash != hashedPassword) return Ok(ApiResponse.SuccessResponse(false));

            dbContext.Users.Where(u => u.Username == dto.Username)
                .ExecuteUpdate(b =>
                    b.SetProperty(u => u.UpdatedAt, DateTime.UtcNow)
                );
            await dbContext.SaveChangesAsync();

            await SignInWith(user.Username, user.Role);
            return Ok(ApiResponse.SuccessResponse(true));
        }

        /// <summary>
        /// 退出登录
        /// </summary>
        [HttpDelete("logout")]
        [Authorize]
        public async Task<IActionResult> Logout()
        {
            await SignOutUser();
            return Ok(ApiResponse.SuccessResponse(true));
        }

        /// <summary>
        /// 获取当前用户信息
        /// </summary>
        [HttpGet("me")]
        [Authorize]
        public async Task<IActionResult> GetCurrentUser()
        {
            var username = User.Identity.Name;
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.Username == username);

            if (user == null || user.IsDeleted) return Ok(ApiResponse.EmptyResponse());

            return Ok(ApiResponse.SuccessResponse(new {
                id = user.UserId,
                name = user.Username,
                avatar = user.Avatar,
                bio = user.Bio,
                role = user.Role,
                created_at = user.CreatedAt,
                last_login = user.UpdatedAt,
            }));
        }


        /// <summary>
        /// 根据用户ID获取用户数据
        /// </summary>
        [HttpGet("{id}")]
        public async Task<IActionResult> GetUserById(int id)
        {
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.UserId == id);

            if (user == null || user.IsDeleted) return Ok(ApiResponse.EmptyResponse());

            return Ok(ApiResponse.SuccessResponse(new
            {
                id = user.UserId,
                name = user.Username,
                avatar = user.Avatar,
                bio = user.Bio,
                role = user.Role,
                created_at = user.CreatedAt,
            }));
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        [Authorize(Roles = "admin")]
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteUser(int id)
        {
            var username = User.Identity.Name;

            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.UserId == id);
            if (user == null || user.IsDeleted) return Ok(false);

            if (user.Username == username)
            {
                return Ok(ApiResponse.ErrorResponse("不能删除自己", 400));
            }

            if (user.Role == "admin")
            {
                return Ok(ApiResponse.ErrorResponse("不能删除管理员", 400));
            }

            user.IsDeleted = true;
            await dbContext.SaveChangesAsync();

            return Ok(ApiResponse.SuccessResponse(true));
        }

        /// <summary>
        /// 设置用户权限
        /// </summary>
        /// <param name="id"></param>
        /// <example>2</example>
        /// <returns></returns>
        [HttpPut("{id}/role")]
        [Authorize(Roles = "admin")]
        public async Task<IActionResult> UpdateUserRole(int id, [FromBody] UpdateRoleDto dto)
        {
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.UserId == id);

            if (user == null || user.IsDeleted) return BadRequest(ApiResponse.ErrorResponse("用户不存在", 400));
            if (user.Role == "admin") return BadRequest(ApiResponse.ErrorResponse("不能修改管理员的权限", 400));
            if (dto.Role != "user" && dto.Role != "mod") return BadRequest(ApiResponse.ErrorResponse("不支持的权限", 400));

            dbContext.Users.Where(u => u.UserId == id)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.Role, dto.Role)
                );
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(user).ReloadAsync();

            return await GetUserById(id);
        }

        /// <summary>
        /// 设置用户个人简介
        /// </summary>
        /// <returns></returns>
        [HttpPut("me/bio")]
        [Authorize]
        public async Task<IActionResult> UpdateUserBio([FromBody] UpdateBioDto dto)
        {
            var username = User.Identity.Name;
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.Username == username);

            if (user == null || user.IsDeleted) return BadRequest(ApiResponse.ErrorResponse("用户不存在", 400));

            dbContext.Users.Where(u => u.UserId == user.UserId)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.Bio, dto.Bio)
                );
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(user).ReloadAsync();

            return await GetUserById(user.UserId);
        }

        /// <summary>
        /// 设置头像
        /// </summary>
        [HttpPut("me/avatar")]
        [Authorize]
        [Consumes("image/png", "image/jpeg")]
        public async Task<IActionResult> UpdateUserAvatar()
        {
            var username = User.Identity.Name;
            var user = await dbContext.Users.FirstOrDefaultAsync(u => u.Username == username);

            if (user == null || user.IsDeleted) return BadRequest(ApiResponse.ErrorResponse("用户不存在", 400));

            var imageBytes = await ImageUtils.ReadImageFromRequest(Request, 300, 300);
            if (imageBytes == null) return BadRequest(ApiResponse.ErrorResponse("无效的文件类型", 400));

            var imageId = Guid.NewGuid();
            dbContext.Images.Add(new Models.Image
            {
                ImageId = imageId,
                Mime = "image/png",
                Content = imageBytes
            });
            await dbContext.SaveChangesAsync();

            dbContext.Users.Where(u => u.UserId == user.UserId)
                .ExecuteUpdate(b =>
                    b.SetProperty(b => b.Avatar, imageId)
                );
            await dbContext.SaveChangesAsync();
            await dbContext.Entry(user).ReloadAsync();

            return await GetUserById(user.UserId);
        }

        /// <summary>
        /// 搜索用户
        /// </summary>
        [HttpGet("query")]
        [Authorize]
        public async Task<IActionResult> SearchUsers(
            [FromQuery] string? keyword = null,
            [FromQuery] int all = 0,
            [FromQuery] int page = 1,
            [FromQuery] int pageSize = 10
        )
        {
            var username = User.Identity?.Name;
            var user = username != null ? await dbContext.Users.FirstOrDefaultAsync(u => u.Username == username) : null;

            var query = dbContext.Users.AsQueryable();
            if (!string.IsNullOrEmpty(keyword))
            {
                query = query.Where(u => !u.IsDeleted && EF.Functions.Contains(u.Username, keyword));
            }
            var withDeleted = (user?.Role == "admin" || user?.Role == "mod") && all != 0;
            if (!withDeleted)
            {
                query = query.Where(u => !u.IsDeleted);
            }
            query = query.OrderBy(u => u.CreatedAt);

            var total = await query.CountAsync();
            var users = await query
                .Skip((page - 1) * pageSize)
                .Take(pageSize)
                .Select(u => new
                {
                    id = u.UserId,
                    name = u.Username,
                    avatar = u.Avatar,
                    deleted = u.IsDeleted,
                    bio = u.Bio,
                    role = u.Role,
                    created_at = u.CreatedAt
                })
                .ToListAsync();

            return Ok(ApiResponse.SuccessResponse(new
            {
                total = total,
                users = users
            }));
        }

        private async Task SignInWith(string name, string role)
        {
            var claims = new List<Claim> {
                new Claim(ClaimTypes.Name, name),
                new Claim(ClaimTypes.Role, role)
            };
            var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
            var principal = new ClaimsPrincipal(identity);

            var authProperties = new AuthenticationProperties
            {
                IsPersistent = true,
                ExpiresUtc = DateTime.UtcNow.AddDays(7)
            };

            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, authProperties);
        }

        private async Task SignOutUser()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        }

        private string GenerateSalt()
        {
            using (var rng = RandomNumberGenerator.Create())
            {
                var saltBytes = new byte[16];
                rng.GetBytes(saltBytes);
                return Convert.ToBase64String(saltBytes);
            }
        }

        private string HashPassword(string password, string salt)
        {
            using (var sha256 = SHA256.Create())
            {
                var saltedPassword = salt + password;
                var bytes = Encoding.UTF8.GetBytes(saltedPassword);
                var hashedBytes = sha256.ComputeHash(bytes);
                return Convert.ToBase64String(hashedBytes);
            }
        }
    }

    /// <summary>
    /// Update role payload
    /// </summary>
    public class UpdateRoleDto
    {
        /// <example>mod</example>
        public required string Role { get; set; }
    }

    /// <summary>
    /// Update bio payload
    /// </summary>
    public class UpdateBioDto
    {
        /// <example>This is a user bio.</example>
        public required string Bio { get; set; }
    }

    /// <summary>
    /// Login payload
    /// </summary>
    public class LoginDto
    {
        /// <example>user</example>
        public required string Username { get; set; }
        /// <example>password</example>
        public required string Password { get; set; }
    }

    /// <summary>
    /// Create payload
    /// </summary>
    public class CreateDto
    {
        /// <example>user</example>
        public required string Role { get; set; }
        /// <example>user</example>
        public required string Username { get; set; }
        /// <example>password</example>
        public required string Password { get; set; }
    }


}
